package com.hzncc.flowable_diboot.convert.bpm;

import cn.hutool.core.util.ArrayUtil;
import com.diboot.core.util.BeanUtils;
import com.hzncc.flowable_diboot.dto.bpm.BpmModelMetaInfoRespDTO;
import com.hzncc.flowable_diboot.entity.FormDesign;
import com.hzncc.flowable_diboot.entity.bpm.BpmCategory;
import com.hzncc.flowable_diboot.entity.bpm.BpmForm;
import com.hzncc.flowable_diboot.util.DateUtils;
import com.hzncc.flowable_diboot.util.JsonUtils;
import com.hzncc.flowable_diboot.vo.bpm.BpmModelCreateReqVO;
import com.hzncc.flowable_diboot.vo.bpm.BpmModelRespVO;
import com.hzncc.flowable_diboot.vo.bpm.BpmModelUpdateReqVO;
import com.hzncc.flowable_diboot.vo.bpm.BpmProcessDefinitionRespVO;
import org.apache.commons.lang3.StringUtils;
import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ProcessDefinition;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 流程模型 Convert
 */
@Mapper
public interface BpmModelConvert {

    BpmModelConvert INSTANCE = Mappers.getMapper(BpmModelConvert.class);

    default List<BpmModelRespVO> buildModelList(List<Model> models,
                                                      Map<String, FormDesign> formMap,
                                                      Map<String, BpmCategory> categoryMap, Map<String, Deployment> deploymentMap,
                                                      Map<String, ProcessDefinition> processDefinitionMap) {
        return models.stream().map(model -> {
            BpmModelMetaInfoRespDTO metaInfo = buildMetaInfo(model);
            FormDesign form = metaInfo != null ? formMap.get(metaInfo.getFormId()) : null;
            BpmCategory category = categoryMap.get(model.getCategory());
            Deployment deployment = model.getDeploymentId() != null ? deploymentMap.get(model.getDeploymentId()) : null;
            ProcessDefinition processDefinition = model.getDeploymentId() != null ? processDefinitionMap.get(model.getDeploymentId()) : null;
            return buildModel0(model, metaInfo, form, category, deployment, processDefinition);
        }).collect(Collectors.toList());
    }

    default BpmModelRespVO buildModel(Model model,
                                      byte[] bpmnBytes) {
        BpmModelMetaInfoRespDTO metaInfo = buildMetaInfo(model);
        BpmModelRespVO modelVO = buildModel0(model, metaInfo, null, null, null, null);
        if (ArrayUtil.isNotEmpty(bpmnBytes)) {
            modelVO.setBpmnXml(new String(bpmnBytes));
        }
        return modelVO;
    }

    default BpmModelRespVO buildModel0(Model model,
                                       BpmModelMetaInfoRespDTO metaInfo, FormDesign form, BpmCategory category,
                                       Deployment deployment, ProcessDefinition processDefinition) {
        BpmModelRespVO modelRespVO = new BpmModelRespVO().setId(model.getId()).setName(model.getName())
                .setKey(model.getKey()).setCategory(model.getCategory())
                .setCreateTime(DateUtils.of(model.getCreateTime()));
        // Form
        if (metaInfo != null) {
            modelRespVO.setFormType(metaInfo.getFormType()).setFormId(metaInfo.getFormId())
                    .setFormCreatePath(metaInfo.getFormCreatePath())
                    .setFormViewPath(metaInfo.getFormViewPath());
            modelRespVO.setIcon(metaInfo.getIcon()).setDescription(metaInfo.getDescription());
        }
        if (form != null) {
            modelRespVO.setFormId(form.getId()).setFormName(form.getFormName());
        }
        // Category
        if (category != null) {
            modelRespVO.setCategoryName(category.getName());
        }
        // ProcessDefinition
        if (processDefinition != null) {
            modelRespVO.setProcessDefinition(BeanUtils.convert(processDefinition,BpmProcessDefinitionRespVO.class));
            modelRespVO.getProcessDefinition().setProcessDefinitionId(processDefinition.getId());
            modelRespVO.getProcessDefinition().setSuspensionState(processDefinition.isSuspended() ?
                    SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode());
            if (deployment != null) {
                modelRespVO.getProcessDefinition().setDeploymentTime(DateUtils.of(deployment.getDeploymentTime()));
            }
        }
        if (StringUtils.isNotEmpty(model.getDeploymentId())){
            modelRespVO.setStatus("1");
        }
        return modelRespVO;
    }

    default void buildModelFromCreateReq(Model model, BpmModelCreateReqVO bean) {
        model.setName(bean.getName());
        model.setKey(bean.getKey());
        model.setCategory(bean.getCategory());
        model.setMetaInfo(buildMetaInfoStr(buildMetaInfo(model), bean.getIcon(), bean.getDescription(), bean.getFormId(), bean.getFormType(), bean.getFormCreatePath(), bean.getFormViewPath()));
    }

    default void buildModelFromUpdateReq(Model model, BpmModelUpdateReqVO bean) {
        model.setName(bean.getName());
        model.setCategory(bean.getCategory());
        model.setMetaInfo(buildMetaInfoStr(buildMetaInfo(model), bean.getIcon(), bean.getDescription(), bean.getFormId(),bean.getFormType(),bean.getFormCreatePath(),bean.getFormViewPath()));
    }

    default String buildMetaInfoStr(BpmModelMetaInfoRespDTO metaInfo,
                                    String icon, String description, String formId,String formType,String formCreatePath,String formViewPath) {
        if (metaInfo == null) {
            metaInfo = new BpmModelMetaInfoRespDTO();
        }
        // 只有非空，才进行设置，避免更新时的覆盖
        if (StringUtils.isNotEmpty(icon)) {
            metaInfo.setIcon(icon);
        }
        if (StringUtils.isNotEmpty(description)) {
            metaInfo.setDescription(description);
        }
        if (Objects.nonNull(formType)) {
            metaInfo.setFormType(formType);
            metaInfo.setFormId(formId);
            metaInfo.setFormCreatePath(formCreatePath);
            metaInfo.setFormViewPath(formViewPath);
        }
        return JsonUtils.toJsonString(metaInfo);
    }

    default BpmModelMetaInfoRespDTO buildMetaInfo(Model model) {
        return JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
    }

}
